package main

import (
	"fmt"
	"log"
	"net"
	"net/rpc"

	"gitee.com/go-course/go9/tree/master/micro/rpc/interface/service"
)

// 实现一个Greet
// GreetService 类, 需要别HelloService接口约束

// var a int = 10
// a 这个变量不用的, 只用接口来完成约束
// var a service.HelloService = &GreetService{}
// var _ service.HelloService = &GreetService{}
// &GreetService{} 这个值也是没用的, 可以使用 空指针代替, 该对象的指针
// (*GreetService)(nil) --> 类型转换(断言)
// int64(64) <==> (int64)(64)  (*int64)(nil)  (*GreetService)(nil)
// 初始化一个类型为GreetService的空指针
var _ service.HelloService = (*GreetService)(nil)

// a := 64
// var b int64 = int64(a)
// fmt.Println(b)

// @HelloService
type GreetService struct {
}

// 功能实现
// 注册的RPC的实现,  必须要满足RPC规范：
// 由于我们是一个rpc服务, 因此参数上面还是有约束： Greet(request string, response string) error
//
//		第一个参数是请求
//		第二个参数是响应
//	 最后返回Error
//
// 可以类比Http handler
func (s *GreetService) Greet(request string, response *string) error {
	*response = fmt.Sprintf("Hello, %s", request)
	return nil
}

// 进程内表用: GreetService{}.Greet()
// 需要引入RPC框架, 来帮我们处理 底层通信/数据交互
// Go 语言内置的RPC net/rpc

func main() {
	// 1. 需要把业务功能类, 注册给RPC框架
	// 其中rpc.Register函数调用会将对象类型中所有满足RPC规则的对象方法注册为RPC函数，
	// 所有注册的方法会放在“HelloService”服务空间之下, GreetService.Greet
	err := rpc.RegisterName("GreetService", new(GreetService))
	if err != nil {
		log.Fatal("RegisterName error:", err)
		return
	}

	// rpc框架需要对外提供 API
	// 然后我们建立一个唯一的TCP链接，
	listener, err := net.Listen("tcp", ":1234")
	if err != nil {
		log.Fatal("ListenTCP error:", err)
		return
	}

	// 通过rpc.ServeConn函数在该TCP链接上为对方提供RPC服务。
	// 没Accept一个请求，就创建一个goroutie进行处理
	for {
		// 获取一个客户端请求(每一个请求就是一个连接)
		conn, err := listener.Accept()
		if err != nil {
			log.Fatal("listener accept error:", err)
		}

		// 需要处理该客户端, 发送给我们的请求
		// rpc 的ServeConn 把请求转接给rpc框架给我们处理(底层通信/数据交互)
		go rpc.ServeConn(conn)
	}
}
